package com.gmss.crawler.service;

import cn.hutool.poi.excel.ExcelUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.alibaba.fastjson.JSON;
import com.gmss.crawler.utils.CommonUtils;
import com.gmss.crawler.utils.CrawlerCommonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.springframework.stereotype.Service;

import java.io.File;
import java.io.InputStream;
import java.util.*;
import java.util.regex.Pattern;

/**
 * 北航计算机学院师资队伍爬取
 */
@Slf4j
@Service
public class BHComputerSchoolCrawlerService {

    // 北航计算机学院师资队伍
    private static final String crawlerPath = "http://scse.buaa.edu.cn/szdw/qtjs.htm";
    // 北航计算机学院师资队伍列表
    private static final String PATH = "http://scse.buaa.edu.cn/szdw/";
    // 个人页面url
    private static final String PERSONAL_PATH = "http://scse.buaa.edu.cn/";
    // 保存个人照片地址
    private static String filePath = "E:\\idea-project\\img\\";
    // excel保存地址
    private static String excelFilePath = "E:\\";

//    private static final Pattern CARD = Pattern.compile("<a target=\"_blank\" href=\"(.*?)\"");

    public static void main(String[] args) {
        parseHtml();
    }

    /**
     * 解析html页面
     */
    private static void parseHtml() {
        long startTime = System.currentTimeMillis();
        try {
            Document doc = CrawlerCommonUtils.getDocument(crawlerPath);
            // 获取师资队伍列表
            Elements imgList = doc.select(".navContent ").select("li").select("a");
            List<Map> list = new ArrayList<>();
            for (int i = 0; i < imgList.size(); i++) {
                Element el = imgList.get(i);
                // 师资队伍职称
                String titleText = el.text();
                // 师资队伍职称列表URL
                String href = el.attr("href");
                Document elementDoc = CrawlerCommonUtils.getDocument(PATH + href);
                // 获取师资队伍列表二级页面a标签
                Elements twoLevelHrefs = elementDoc.select(".lm_list1").select("a");
                String twoLevelHref = "";
                String twoLevelName = "";
                for (int j = 0; j < twoLevelHrefs.size(); j++) {
                    Element twoLevelElement = twoLevelHrefs.get(j);
                    // 获取师资队伍列表二级页面a标签URL
                    twoLevelHref = twoLevelElement.attr("href");
                    // 姓名
                    twoLevelName = twoLevelElement.select("span").text();
                    // 个人信息处理
                    personalData(list, titleText, twoLevelHref, twoLevelName);
                }
            }

            // 数据写入excel
            boolean bool = saveExcel(list);
            long endTime = System.currentTimeMillis();
            log.info("bool:{},excel:{},cost:{}", bool, bool ? "成功" : "失败", endTime - startTime);

        } catch (Exception e) {
            long endTime = System.currentTimeMillis();
            log.info("cost:{}", endTime - startTime);
            log.error("Exception:{}", e);
        } finally {
        }
    }

    /**
     * 保存excel
     *
     * @param list
     * @return
     */
    private static boolean saveExcel(List<Map> list) {
        String fileName = "北航计算机学院-师资队伍信息，-.xlsx";
        String localFilePath = excelFilePath + File.separator + fileName;
        List<LinkedHashMap<String, Object>> rows = convertExcel(list);
        return fileMethod(fileName, localFilePath, rows);
    }

    /**
     * 个人信息数据封装
     *
     * @param list
     * @param titleText
     * @param twoLevelHref
     * @param twoLevelName
     * @throws InterruptedException
     */
    private static void personalData(List<Map> list, String titleText, String twoLevelHref, String twoLevelName) throws InterruptedException {
        if (StringUtils.isNotBlank(twoLevelName)) {
            // 处理网页防爬，300-500ms随机
            Thread.sleep(CommonUtils.randomRange(300, 500));
            // 师资队伍的姓名与个人信息的url
            twoLevelHref = twoLevelHref.substring(6, twoLevelHref.length());
            Document personalDoc = CrawlerCommonUtils.getDocument(PERSONAL_PATH + twoLevelHref);

//                        if (StringUtils.equalsAny(twoLevelName, "齐越", "李波", "牛建伟")) {
//                            log.debug("");
//                        }
            // 个人介绍，统一样式的
            Element introduceP2Element = personalDoc.getElementById("introduceP2");
            String introduceP2 = "";
            if (null != introduceP2Element) {
                introduceP2 = introduceP2Element.text();
            }
            // 不是统一样式,代表人员：李波、齐越
            if (StringUtils.isBlank(introduceP2)) {
                Elements pStyles = personalDoc.getElementById("vsb_content").select("p").select("span");
                for (Element element : pStyles) {
                    introduceP2 += element.text();
                }
            }

            Elements personalDivs = personalDoc.getElementById("vsb_content").select(".card_detail_content").select(".card_detail");
            // 获取个人图片
            Elements imgDivs = personalDoc.getElementById("vsb_content").select(".card_detail_content").select("div").select("img");
            String imgUrl = imgDivs.get(0).absUrl("src");
            String fileName = "" + UUID.randomUUID().toString().replaceAll("-", "") + ".jpg";
            // 个人图片保存到本地
            getPersonalImgSave(imgUrl, filePath, fileName);
            Map dataMap = new HashMap();
            dataMap.put("个人介绍", introduceP2.replaceAll(" ", "").replaceAll(" ", ""));
            List<String> personTitleList = new ArrayList<>();
            personTitleList.add(titleText);
            dataMap.put("职称", personTitleList);

            File file = new File(filePath + fileName);
            if (file.exists())
                dataMap.put("img", filePath + fileName);
            for (int k = 0; k < personalDivs.size(); k++) {
                Element personalEl = personalDivs.get(k);
                String personalData = personalEl.select("div").text();
                String[] datas = personalData.replaceAll("：", ":").split(":");
                String title = "";
                String value = "";
                if (datas.length == 2) {
                    title = datas[0].replaceAll(" ", "").replaceAll(" ", "");
                    if (StringUtils.isNotBlank(datas[1]))
                        value = datas[1].replaceAll(" ", "").replaceAll(" ", "");
                } else if (datas.length == 3) {
                    // 处理个人主页中的http://情况，之前通过：分割了。
                    title = datas[0].replaceAll(" ", "").replaceAll(" ", "");
                    String value1 = "";
                    String value2 = "";
                    if (StringUtils.isNotBlank(datas[1])) {
                        value1 = datas[1].replaceAll(" ", "").replaceAll(" ", "");
                        if (StringUtils.isBlank(value1))
                            value1 = "http";
                    }
                    if (StringUtils.isNotBlank(datas[2])) {
                        value2 = datas[2].replaceAll(" ", "").replaceAll(" ", "");
                    }
                    value = value1 + ":" + value2;

                }
                // 代表人员：牛建伟
                if (StringUtils.equalsAny(title, "电子邮箱")) {
                    dataMap.put("邮箱", value);
                } else {
                    dataMap.put(title, value);
                }
            }
            // 同一个人有多个职称时，职称进行合并，且保留一条数据。姓名与邮箱相同认为是同一个人。
            for (Map personMap : list) {
                if (StringUtils.equals(twoLevelName, personMap.get("姓名").toString()) && StringUtils.equals(dataMap.get("邮箱").toString(), personMap.get("邮箱").toString())) {
                    List<String> names = (List<String>) personMap.get("职称");
                    names.add(titleText);
                    dataMap.clear();
                    break;
                }
            }
            log.info("个人信息：{}", JSON.toJSONString(dataMap));
            /*if (MapUtils.isNotEmpty(dataMap))
                list.add(dataMap);*/
        }
    }

    /**
     * 个人照片保存到本地
     */
    private static void getPersonalImgSave(String imgUrl, String filePath, String fileName) {
        byte[] btImg = CrawlerCommonUtils.getImageFromNetByUrl(imgUrl);
        if (null != btImg && btImg.length > 0) {
            log.debug("读取到：" + btImg.length + " 字节");
            CrawlerCommonUtils.writeImageToDisk(btImg, filePath, fileName);
        } else {
            log.info("没有从该连接获得内容");
        }
    }

    /**
     * 封装写入excel信息
     *
     * @param lists
     * @return
     */
    public static List<LinkedHashMap<String, Object>> convertExcel(List<?> lists) {
        List<LinkedHashMap<String, Object>> rows = new ArrayList<>(lists.size());
        Object object = lists.get(0);
        if (object instanceof Map) {
            List<Map> list = (List<Map>) lists;
            list.forEach((Map map) -> {
                LinkedHashMap<String, Object> row = new LinkedHashMap<>(list.size());
                row.put("姓名", map.containsKey("姓名") ? map.get("姓名") : "");
                row.put("职称", map.containsKey("职称") ? String.join(",", (List) map.get("职称")) : "");
                row.put("个人照片地址", map.containsKey("img") ? map.get("img") : "");
                row.put("职位", map.containsKey("职位") ? map.get("职位") : "");
                row.put("座机", map.containsKey("座机") ? map.get("座机") : "");
                row.put("邮编", map.containsKey("邮编") ? map.get("邮编") : "");
                row.put("办公地址", map.containsKey("办公地址") ? map.get("办公地址") : "");
                row.put("电子邮箱", map.containsKey("邮箱") ? map.get("邮箱") : "");
                row.put("个人主页", map.containsKey("个人主页") ? map.get("个人主页") : "");
                row.put("个人介绍", map.containsKey("个人介绍") ? map.get("个人介绍") : "");
                rows.add(row);
            });
        }
        return rows;
    }

    /**
     * 数据定入excel
     *
     * @param fileName
     * @param localFilePath
     * @param rows
     * @return
     */

    public static boolean fileMethod(String fileName, String localFilePath, List<LinkedHashMap<String, Object>> rows) {
        ExcelWriter writer = null;
        try {
            // 临时文件写入到服务器路径里
            File localFile = new File(localFilePath);
            if (!localFile.exists())
                localFile.exists();
            writer = ExcelUtil.getWriter(localFilePath);
            writer.write(rows);
        } catch (Exception e) {
            log.error("上传文件{}到文件服务器异常", localFilePath, e);
            return false;
        } finally {
            writer.close();
        }

        return true;
    }

}
